#include "my_ano.h"
#include "usart.h"
#include "ring_queue.h"
#include <string.h>
/**
  ******************************************************************************
  * @file    	my_ano.c
  * @author  	李焰权
  * @brief   	匿名上位机V7.0最新版本通信协议文件
  * @function 实现了灵活格式帧的通信，可自由选择变量，进行字节数计算和拼凑，来查看波形
  *						实现了自定义参数的读和写，可以通过上位机进行人机交互，对系统进行简单控制
	* @warnings 本代码不作飞控用途，涉及飞控类的通信请用户自行完善
  ******************************************************************************
**/




par_struct target_val;										//目标值参数
static ano_frameStruct send_frame_struct;	//(发送)通信帧结构体
static ano_frameStruct rec_frame_struct;					//(接收)通信帧结构体

/**
  * @brief   初始化通信帧结构体,使用前必须调用
  * @param   
  * @retval 
  **/
void ano_frame_init(void)
{
	send_frame_struct.head=rec_frame_struct.head=FRAME_HEADER;
	send_frame_struct.target_addr=rec_frame_struct.target_addr=GENERAL_OUTPUT_ADDR;
	send_frame_struct.function_id=0XFF;//无定义的功能ID,目的是为了初始化瞬间不做任何动作


	memset(send_frame_struct.data,0,40);//缓存默认全部置0
	memset(rec_frame_struct.data,0,40);
}
/**
  * @brief   复位通信帧结构体，ano_frame_init()必须要运行过一次
  * @param   通信帧结构体对象
  * @retval 
  **/
void ano_frame_reset(ano_frameStruct* frame)
{
  frame->function_id=0XFF;						
  frame->data_len=0;
  memset(frame->data,0,40);
  frame->add_check=0;
  frame->sum_check=0;
}
/**
  * @brief   参数结构体内成员的配置
  * @param   参数结构体对象，参数ID，参数值
  * @retval 
  **/
void ano_par_struct_config(par_struct* parameter,uint16_t par_id,int32_t par_val)
{
	parameter->par_id=par_id;
	parameter->par_val=par_val;
}
/**
  * @brief   通信帧校验计算，并传递(发送时用)
  * @param   通信帧结构体
  * @retval 
  **/
static void ano_check_transmit(ano_frameStruct* frame)
{
	frame->sum_check=0;
	frame->add_check=0;
	
	for(uint32_t i=0;i<4;i++)
	{
	  frame->sum_check+= *(uint8_t*)(&frame->head+i);
	  frame->add_check+=frame->sum_check;
	}
	for(uint32_t i=0;i<frame->data_len;i++)
	{
	  frame->sum_check+=*((uint8_t*)(frame->data)+i);
	  frame->add_check+=frame->sum_check;
	} 
 }
/**
  * @brief   通信帧校验检查(接收时用)
  * @param   通信帧结构体
 * @retval   1：校验成功 0:校验失败
  **/
static uint8_t ano_check(ano_frameStruct* frame)
{
	uint8_t sum_check=0;
	uint8_t add_check=0;

	for(uint32_t i=0;i<4;i++)
	{
	  sum_check+= *(uint8_t*)(&frame->head+i);
	  add_check+=sum_check;
	}
	for(uint32_t i=0;i<frame->data_len;i++)
	{
	  sum_check+=*((uint8_t*)(frame->data)+i);
	  add_check+=sum_check;
	}

	if((sum_check==frame->sum_check)&&(add_check==frame->add_check))
	 return 1;
	else
	 return 0;
}
/**
  * @brief   通信帧结构体转化为线性数组
  * @param   要转换的通信帧，缓存数组
  * @retval 
  **/
static void frame_turn_to_array(ano_frameStruct* frame,uint8_t*str)
{
	memcpy(str,(uint8_t*)frame,4);
	memcpy(str+4,(uint8_t*)frame->data,frame->data_len);
	memcpy(str+4+frame->data_len,(uint8_t*)(&frame->sum_check),2);
}
/**
  * @brief  匿名串口发送
  * @param  字符串，数据字节个数
  * @retval 
  */
static void ano_usart_send(uint8_t*str,uint16_t num)
{
 uint16_t cnt=0;
 do
	{
		HAL_UART_Transmit(&huart1,((uint8_t*)(str))+cnt,1,1000);
		cnt++;
	}while(cnt<=num);
}
 /**
  * @brief  向上位机发送ASCII字符串
  * @param  color:希望上位机显示的字符串颜色，str：要发送的字符串
  * @retval 
  */
void ano_send_string(uint8_t color,char* str)
{
	uint8_t i=0,cnt=0;
	uint8_t buff[46];										
	memset(send_frame_struct.data,0,40);
	send_frame_struct.function_id=0XA0;//信息输出--字符串
	send_frame_struct.data[cnt++]=color;
	
	while(*(str+i)!='\0')
	{
		send_frame_struct.data[cnt++]=*(str+i++);
		if(cnt>40)
			break;
	}
	send_frame_struct.data_len=cnt;
	
	ano_check_transmit(&send_frame_struct);
	frame_turn_to_array(&send_frame_struct,buff);
	ano_usart_send(buff,6+send_frame_struct.data_len);
}

/**
  * @brief  向上位机发送ASCII字符串+数字组合
  * @param  value:32位的数值，str：要发送的字符串
  * @retval 
  */
void ano_send_message(char* str,int32_t value)
{
	uint8_t i=0,cnt=0;
	uint8_t buff[46];										
	memset(send_frame_struct.data,0,40);
	send_frame_struct.function_id=0XA1;	//信息输出--字符串+数字
	
	
	send_frame_struct.data[cnt++]=BYTE0(value);
	send_frame_struct.data[cnt++]=BYTE1(value);
	send_frame_struct.data[cnt++]=BYTE2(value);
	send_frame_struct.data[cnt++]=BYTE3(value);
	
	while(*(str+i)!='\0')
	{
		send_frame_struct.data[cnt++]=*(str+i++);
		if(cnt>40)
			break;
	}
	
	send_frame_struct.data_len=cnt;
	
	ano_check_transmit(&send_frame_struct);
	frame_turn_to_array(&send_frame_struct,buff);
	ano_usart_send(buff,6+send_frame_struct.data_len);
}
 /**
  * @brief  发送数据校验帧
  * @param  id_get:接收到的通信帧功能id，sc_get:接收到的通信帧校验，ac_get：接收到的通信帧附加校验
  * @retval 
  */
static void ano_send_check_frame(uint8_t id_get,uint8_t sc_get,uint8_t ac_get)
{
	uint8_t buff[46];
	
	memset(send_frame_struct.data,0,40);
	send_frame_struct.function_id=0X00;
	send_frame_struct.data_len=3;												//这里要随传递的参数自行计算，最好不要用sizeof,会减慢通信速度
	
	send_frame_struct.data[0]=id_get;
	send_frame_struct.data[1]=sc_get;
	send_frame_struct.data[2]=ac_get;
	
	ano_check_transmit(&send_frame_struct);
	frame_turn_to_array(&send_frame_struct,buff);


	ano_usart_send(buff,6+send_frame_struct.data_len);
}
 
/**
  * @brief  发送灵活格式帧
  * @param  id:0xF1~0XFA，x_coordinate:风力摆x轴目标值 ，y_coordinate：风力摆y轴目标值
  *         !!!要传多少个参数完全可以自己进行计算，最高只支持40字节的数据，低位先输出
  * @retval 
  */
void ano_send_flexible_frame(uint8_t id,int32_t x_target,int32_t x_actual,int32_t y_target,int32_t y_actual)
{
	uint8_t buff[46];
	
	memset(send_frame_struct.data,0,40);
	send_frame_struct.function_id=id;
	send_frame_struct.data_len=16;												
	
	send_frame_struct.data[0]=BYTE0(x_target);
	send_frame_struct.data[1]=BYTE1(x_target);
	send_frame_struct.data[2]=BYTE2(x_target);
	send_frame_struct.data[3]=BYTE3(x_target);

	send_frame_struct.data[4]=BYTE0(x_actual);
	send_frame_struct.data[5]=BYTE1(x_actual);
	send_frame_struct.data[6]=BYTE2(x_actual);
	send_frame_struct.data[7]=BYTE3(x_actual);
	
	send_frame_struct.data[8]=BYTE0(y_target);
	send_frame_struct.data[9]=BYTE1(y_target);
	send_frame_struct.data[10]=BYTE2(y_target);
	send_frame_struct.data[11]=BYTE3(y_target);
	
	send_frame_struct.data[12]=BYTE0(y_actual);
	send_frame_struct.data[13]=BYTE1(y_actual);
	send_frame_struct.data[14]=BYTE2(y_actual);
	send_frame_struct.data[15]=BYTE3(y_actual);
	
	ano_check_transmit(&send_frame_struct);
	frame_turn_to_array(&send_frame_struct,buff);


	ano_usart_send(buff,6+send_frame_struct.data_len);
}
/**
  * @brief  上位机发送参数通信帧
  * @param  par_id:参数id，par_val：参数值
  * @retval 
  */
void ano_send_parameter_frame(uint16_t par_id,int32_t par_val)
{
	uint8_t buff[46];
	memset(send_frame_struct.data,0,40);
	send_frame_struct.function_id=0XE2;//参数写入反馈
	send_frame_struct.data_len=6;
	/*这里固定*/
	send_frame_struct.data[0]=BYTE0(par_id);
	send_frame_struct.data[1]=BYTE1(par_id);

	send_frame_struct.data[2]=BYTE0(par_val);
	send_frame_struct.data[3]=BYTE1(par_val);
	send_frame_struct.data[4]=BYTE2(par_val);
	send_frame_struct.data[5]=BYTE3(par_val);

	ano_check_transmit(&send_frame_struct);
	frame_turn_to_array(&send_frame_struct,buff);
	ano_usart_send(buff,6+send_frame_struct.data_len);
}

/**
  * @brief  根据接收到的参数读写类帧，反馈信息回上位机
  * @param  par_id:参数id，par_val：参数值
  * @retval 
  */
static void ano_parameter_feedback(ano_frameStruct* frame,par_struct* parStruct)
{
	uint16_t id=0;
	if(ano_check(frame))
	{ 
	 id=frame->data[0]+(frame->data[1]<<8);
	 parStruct->par_id=frame->data[0]+(frame->data[1]<<8);
		if(frame->function_id==0XE0)
		{
			/*功能触发类数据帧默认只有0X01和0X10两种功能，可以自行丰富通信规则*/
			switch (frame->data[0])
			{
				case 0X01:
				{
					//things to do
					break;
				}
				case 0X10:
				{
					//things to do
					break;
				}
				default:
					break;
			}	
			ano_send_check_frame(frame->function_id,frame->sum_check,frame->add_check);//多发几次
		}
		else if (frame->function_id==0XE1)//上位机参数读取，下位机反馈
	 {		 	
		 switch (parStruct->par_id)
		 {
			 case 1:
			 {
				 ano_send_parameter_frame(parStruct->par_id,PRO_ADDR);//将设备伪装成拓空者飞控
				 break;
			 }
			 default:
			 {
				//上位机读取下位机的值,多发几次
				ano_send_parameter_frame(parStruct->par_id,parStruct->par_val);
				break;
			 }
		 }
	 }
		else if(frame->function_id==0XE2)																//上位机改变了下位机的值并校验反馈
	 {
			parStruct->par_val=frame->data[2]+(frame->data[3]<<8)+(frame->data[4]<<16)+(frame->data[5]<<24);
			ano_send_check_frame(frame->function_id,frame->sum_check,frame->add_check);
	 }
	}
}
/**
  * @brief  (实际是单字节读取，并赋值给结构体)上位机读取下位机参数，并反馈
  * @param  
  * @retval 
  */
void ano_read_one_byte(uint8_t data)
{
	static uint8_t status=HEAD_PART;
	static uint8_t cnt=0;
	
	switch (status)
	{
	 case HEAD_PART:
	 {
		 if(data==0XAA)								//检测到帧头，经过一番折腾，这里一定要有，不然操作多了就会失灵，因为通信帧已经全乱了
		 {
		 status=ADDR_PART;
		 ano_frame_reset(&rec_frame_struct);
		 }
		break;
	 }
	 case ADDR_PART:
	 {
		status=ID_PART;
		rec_frame_struct.target_addr=data;
		break;
	 }
	 case ID_PART:
	 {
		rec_frame_struct.function_id=data;
		if((rec_frame_struct.function_id==0XE0)||(rec_frame_struct.function_id==0XE1)||(rec_frame_struct.function_id==0XE2))
			status=DATA_LEN_PART;
		else
		{
			status=HEAD_PART;
			ano_frame_reset(&rec_frame_struct);
		}
		break;	
	 }
	 case DATA_LEN_PART:
	 {
		if(data>40)
		{
		 status=HEAD_PART;
		 ano_frame_reset(&rec_frame_struct);
		}
		else
		{
		rec_frame_struct.data_len=data;
		status=DATA_PART;
		}
	    break;
	 }
	 case DATA_PART:
	 {
		*(rec_frame_struct.data+cnt)=data; 
		cnt++;
		if(cnt>=rec_frame_struct.data_len)
		{
			status=SC_PART;
			cnt=0;
		}
		break;
	 }
	 case SC_PART:
	 {
		 rec_frame_struct.sum_check=data;
		 status=AC_PART;
		 break;
	 }
	 case AC_PART:
	 {
		rec_frame_struct.add_check=data;
		status=HEAD_PART; 
		ano_parameter_feedback(&rec_frame_struct,&target_val);
		break;
	 }
	}
}